import io, json, os
import ui
from ..utils import post
from ..wrapper import subthread, withWaitSound
from .. import constants, settings
# 接口地址
URL = 'https://api.caiyunapp.com/v2.5/dmkCLg6hlAU05KYM/%s/realtime.json?unit=metric:v2'
SELF_DIR = os.path.dirname(__file__) # 自身目录
skyconMap = {} # 天气现象映射表
with open(os.path.join(SELF_DIR, 'skycon.txt'), 'r', encoding = constants.CHARSET) as f:
    for line in f.readlines():
        code, name = line.strip().split('\t')
        skyconMap[code] = name
windSet = set() # 风力表
with open(os.path.join(SELF_DIR, 'wind.txt'), 'r', encoding = constants.CHARSET) as f:
    for line in f.readlines():
        speedRange, name = line.strip().split('\t')
        windSet.add((speedRange, name,))
areaSet = set() # 地区表
with open(os.path.join(SELF_DIR, 'areas.txt'), 'r', encoding = constants.CHARSET) as f:
    for line in f.readlines():
        line = line.strip()
        if not line or line.startswith('#'):continue
        adcode, lng, lat, province, city, district, formattedAddress = line.split(',')
        areaSet.add((adcode, lng, lat, province, city, district, formattedAddress,))
# 获取风力描述
def getWindName(speed): # km/h
    for speedRange, name in windSet:
        start, end = speedRange.split('-')
        if float(start) <= speed and float(end) > speed:
            return name
# 获取方向描述
def getDirectionName(direction):
    names = '北,北东北,东北,东东北,东,东东南,东南,南东南,南,南西南,西南,西西南,西,西西北,西北,北西北,北'.split(',')
    return names[int((direction + 11.25) / 22.5)]
# 根据省市区的名称获取经纬度
def getLocationList(area): # 返回符合条件的经纬度和具体地址的列表
    province = area[0]
    city = '' if len(area) < 2 else area[1]
    district = '' if len(area) < 3 else area[2]
    if not province:
        raise Exception('Please specify the province in the area parameter.')
    if not city:
        raise Exception('Please specify the city in the area parameter.')
    # 先根据省份筛选城市
    cities = []
    for item in areaSet:
        if item[3].startswith(province):
            cities.append(item)
    if not cities:
        raise Exception('Invalid province "%s"' % province)
    # 根据城市筛选县区
    districts = []
    for item in cities:
        if item[4].startswith(city):
            districts.append(item)
    # 拿到有用的信息
    ret = []
    for item in districts:
        if item[5] == district or (district and item[5].startswith(district)):
            ret.append((item[1], item[2], item[6],))
    return ret
# 调用接口获取天气状况
def getWeather(location): # location是经纬度
    # 发起网络请求
    print(location)
    ret = post(URL % location)
    print(ret)
    if not ret:
        raise Exception('No result.')
    # 解析响应数据
    ret = json.loads(ret.decode())
    if not ret or ret['status'] != 'ok':
        raise Exception('Parsing failed.')
    # 从响应数据中读取结果数据
    ret = ret['result']
    if not ret:
        raise Exception('No result.')
    # 数据拼接
    buff = io.StringIO()
    realtime = ret['realtime']
    skycon, temperature, apparentTemperature, humidity, cloudrate, visibility, pressure = realtime['skycon'], realtime['temperature'], realtime['apparent_temperature'], realtime['humidity'], realtime['cloudrate'], realtime['visibility'], realtime['pressure']
    # 基本数据
    buff.write(f'天气： {skyconMap[skycon]}\n')
    buff.write(f'温度： {temperature}℃ （体感： {apparentTemperature}℃）\n')
    buff.write(f'湿度： {humidity}(0~1)\n')
    buff.write(f'云量： {cloudrate}(0~1)\n')
    buff.write(f'能见度： {visibility}km\n')
    buff.write(f'气压： {pressure}Pa\n')
    # 降水数据
    precipitation = realtime['precipitation']
    if precipitation:
        if 'nearest' in precipitation.keys():
            local, nearest = precipitation['local'], precipitation['nearest']
            buff.write(f'降水量： 本地 {local["intensity"]}mm/hr， 距离最近{nearest["distance"]}km {nearest["intensity"]}mm/hr\n')
        else:
            local = precipitation['local']
            buff.write(f'降水量： {local["intensity"]}mm/hr\n')
    # 风速、风向数据
    wind = realtime['wind']
    if wind:
        speed, direction = wind['speed'], wind['direction']
        buff.write(f'风速： {speed}km/hr 【{getWindName(speed)}】\n')
        buff.write(f'风向： {direction}° （{getDirectionName(direction)}）\n')
    # 空气指数数据
    airQuality = realtime['air_quality']
    if airQuality:
        pm25, pm10, o3, so2, no2, co, aqi, description = airQuality['pm25'], airQuality['pm10'], airQuality['o3'], airQuality['so2'], airQuality['no2'], airQuality['co'], airQuality['aqi'], airQuality['description']
        buff.write(f'空气指数： {aqi["chn"]}（{description["chn"]}）， pm2.5 {pm25}， pm1.0 {pm10},， 臭氧 {o3}， 二氧化硫 {so2}， 二氧化氮 {no2}， 一氧化氮 {co}\n')
    # 生活指数数据
    lifeIndex = realtime['life_index']
    if lifeIndex:
        comfort, ultraviolet = lifeIndex['comfort'], lifeIndex['ultraviolet']
        buff.write(f'生活指数： 舒适度 {comfort["index"]}（{comfort["desc"]}）， 紫外线 {ultraviolet["index"]}（{ultraviolet["desc"]}）')
    res = buff.getvalue()
    buff.close()
    return res
@withWaitSound
@subthread
def broadcastWeather():
    # 读取用户关注的天气地区
    area = settings.getArea()
    try:
        buff = io.StringIO()
        # 容错处理，允许用户输入的地区不包括县区，这样有可能有多个经纬度
        for location in getLocationList(area):
            ui.message(f'正在获取 {location[2]} 的天气信息')
            res = getWeather(f'{location[0]},{location[1]}')
            if not res:continue
            # 标题
            buff.write(f'<h1>{location[2]}</h1>')
            # 内容
            buff.write('<br />'.join(res.split('\n')))
        # 展示结果
        ui.browseableMessage(buff.getvalue(), f'天气详情（{",".join(area)}）', True)
    except Exception as e:
        ui.message(f'{e}')
    finally:
        buff.close()